﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BIG=System.Numerics.BigInteger;
using System.Security.Cryptography;

namespace PodpisyElektorniczne.Classes
{
    public class SkdlFactory
    {
        protected BIG R { get; set; }
        protected BIG Order { get; set; }
        protected int Lenght { get; set; }
        protected BIG KeyX { get; set; }
        protected Skdl Skdl { get; set; }


        ///<summary>
        ///use only for verification
        ///</summary>
        public SkdlFactory(Skdl skdl, BIG order, int lenght)
        {
            Skdl = skdl;
            Order = order;
            Lenght = lenght;
        }
        ///<summary>
        ///use for creation of signature
        ///</summary>
        public SkdlFactory(BIG order, int lenght)
        {
            Order = order;
            Lenght = lenght;
            GenerateRandomR(order, lenght);
            Skdl = new Skdl();
        }


        ///<summary>
        ///Procedure to generate skdl single instance
        ///</summary>
        public Skdl BuildSignature(BIG g, BIG y, BIG msg)
        {
            try
            {
                var skdl = new Skdl();
                var hashArgument = string.Format("{0}{1}{2}{3}",g,y, BIG.ModPow(g,R,Order),msg); // jeśli liczę tutaj modulo to czy powinno to być również uwzględnione w weryfikacji?
                skdl.SetresultC(new BIG( new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(hashArgument))));
                skdl.SetResultS(
                        (R - BIG.Multiply(skdl.ResultC,KeyX))
                    );
                return skdl;
            }
            catch (Exception ex)
            {
                return default(Skdl);
            }
        }
        ///<summary>
        ///Procedure to verify the correctness of Skdl on the basis passed arguments.
        ///</summary>
        public bool VerifySignature(BIG g, BIG y, BIG msg)
        {
            try
            {
                var hashArgument = string.Format("{0}{1}{2}{3}", g, y, 
                    BIG.Multiply(BIG.ModPow(g, Skdl.ResultS, Order), BIG.ModPow(y, Skdl.ResultC,Order)),msg);

                var md5 = new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(hashArgument));

                return (Skdl.ResultC == new BIG(md5));
            }
            catch (Exception ex)
            {
                return false;
            }           
        }

        protected void GenerateRandomR(BIG order, int lenght)
        {
            var rng = new RNGCryptoServiceProvider();
            var rBytes= new byte[lenght];
            while((new BIG(rBytes)).Sign <0)
                rng.GetBytes(rBytes);

            R = new BIG(rBytes);
        }


    }
}
